﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using DevComponents.DotNetBar.Controls;
using DevComponents.DotNetBar;
using ESRI.ArcGIS.Carto;
using DevComponents.AdvTree;
using System.IO;
using System.Drawing;
using ESRI.ArcGIS.Controls;
using System.Runtime.InteropServices;
using PlanningGIS.ArcGIS.Custom;
using System.Windows.Forms;
using ESRI.ArcGIS.Geodatabase;
using PlanningGIS.ArcGIS;

namespace PlanningGIS.Engine.Controls
{
    /// <summary>
    /// 图层控件基础类
    /// </summary>
    public class LayersBase
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        public LayersBase()
        {
            this.FeatureType = zjgisFeatureType.All;
            this.ShapeType = zjgisShapeType.All;
        }

        #region 属性、变量
        /// <summary>
        /// 获取或设置是否存在根节点
        /// </summary>
        public bool HasRoot { get; set; }

        /// <summary>
        /// 获取或设置扩展的节点
        /// </summary>
        public string[] NodesExpand { get; set; }

        /// <summary>
        /// 获取或设置复选框是否可见
        /// </summary>
        public bool CheckBoxVisiable { get; set; }
        
        /// <summary>
        /// 获取或设置需要控制的图层类型
        /// </summary>
        public zjgisFeatureType FeatureType { get; set; }
        
        /// <summary>
        /// 获取或设置需要控制的图层空间数据类型
        /// </summary>
        public zjgisShapeType ShapeType { get; set; }

        /// <summary>
        /// 获取或设置图层组是否可选
        /// </summary>
        public bool CompositeLayerEnabled { get; set; }

        /// <summary>
        /// 是否只显示可见图层
        /// </summary>
        private bool _IsOnlyVisiable = false;

        /// <summary>
        /// 获取或设置是否只显示可见图层
        /// </summary>
        public bool IsOnlyVisiable
        {
            get
            {
                return _IsOnlyVisiable;
            }
            set
            {
                if (_IsOnlyVisiable.Equals(value)) return;
                _IsOnlyVisiable = value;
                if (_HookHelper == null) return;
                InitLayers();
            }
        }

        ///// <summary>
        ///// 获取或设置图层组是否可选
        ///// </summary>
        //public bool CompositeLayerEnabled
        //{
        //    get
        //    {
        //        return _CompositeLayerEnabled;
        //    }
        //    set
        //    {
        //        _IsOnlyVisiable = value;
        //    }
        //}

        /// <summary>
        /// 是否只显示可选图层
        /// </summary>
        private bool _IsOnlySelected = false;
        /// <summary>
        /// 获取或设置是否只显示可选图层
        /// </summary>
        public bool IsOnlySelected
        {
            get
            {
                return _IsOnlySelected;
            }
            set
            {
                if (_IsOnlySelected.Equals(value)) return;
                _IsOnlySelected = value;
                if (_HookHelper == null) return;
                InitLayers();
            }
        }
        
        /// <summary>
        /// 获取或设置图层节点集合对象
        /// </summary>
        public NodeCollection Nodes { get; set; }

        /// <summary>
        /// 关联的地图控件
        /// </summary>
        private IHookHelper _HookHelper = null;

        /// <summary>
        /// toc控件
        /// </summary>
        private ITOCControl2 _TocControl = null;

        /// <summary>
        /// 选择的节点
        /// </summary>
        public Node SelectedNode { get; set; }
        #endregion

        #region 注册事件

        /// <summary>
        /// 注册事件
        /// </summary>
        private void RegEvent()
        {
            IActiveViewEvents_Event pAvEvents = _HookHelper.ActiveView as IActiveViewEvents_Event;
            pAvEvents.ItemAdded += new IActiveViewEvents_ItemAddedEventHandler(pAvEvents_ItemAdded);
            pAvEvents.ItemDeleted += new IActiveViewEvents_ItemDeletedEventHandler(pAvEvents_ItemDeleted);
            pAvEvents.ItemReordered += new IActiveViewEvents_ItemReorderedEventHandler(pAvEvents_ItemReordered);
        }

        /// <summary>
        /// 反注册事件
        /// </summary>
        private void UnRegEvent()
        {
            IActiveViewEvents_Event pAvEvents = _HookHelper.ActiveView as IActiveViewEvents_Event;
            pAvEvents.ItemAdded -= new IActiveViewEvents_ItemAddedEventHandler(pAvEvents_ItemAdded);
            pAvEvents.ItemDeleted -= new IActiveViewEvents_ItemDeletedEventHandler(pAvEvents_ItemDeleted);
            pAvEvents.ItemReordered -= new IActiveViewEvents_ItemReorderedEventHandler(pAvEvents_ItemReordered);
        }

        /// <summary>
        /// 地图改变事件
        /// </summary>
        /// <param name="newMap"></param>
        void mapctrlEvent_OnMapReplaced(object newMap)
        {
            InitLayers();
            UnRegEvent();
            RegEvent();
        }

        /// <summary>
        /// 图层树便签改变事件
        /// </summary>
        /// <param name="X"></param>
        /// <param name="Y"></param>
        /// <param name="newLabel"></param>
        /// <param name="CanEdit"></param>
        void tocEvent_OnEndLabelEdit(int X, int Y, string newLabel, ref bool CanEdit)
        {
            IBasicMap map = null;
            ILayer layer = null;
            object other = null;
            object index = null;
            esriTOCControlItem item = esriTOCControlItem.esriTOCControlItemNone;

            _TocControl.HitTest(X, Y, ref  item, ref map, ref layer, ref other, ref  index);
            if (layer != null)
            {
                UpdateName(layer, newLabel, this.Nodes);
            }
        }
        
        /// <summary>
        /// 图层从新排序事件
        /// </summary>
        /// <param name="Item"></param>
        /// <param name="toIndex"></param>
        void pAvEvents_ItemReordered(object Item, int toIndex)
        {
            InitLayers();
        }

        /// <summary>
        /// 移除图层事件
        /// </summary>
        /// <param name="Item"></param>
        void pAvEvents_ItemDeleted(object Item)
        {
            DeleteNode(Item as ILayer, this.Nodes);
        }

        /// <summary>
        /// 添加图层事件
        /// </summary>
        /// <param name="Item"></param>
        void pAvEvents_ItemAdded(object Item)
        {
            AddLayer(Item as ILayer, null, 0);
        }
        #endregion

        #region 设置地图中的图层
        
        /// <summary>
        /// 初始化图层列表事件
        /// </summary>
        private void InitLayers()
        {
            this.Nodes.Clear();
            if (_HookHelper == null || _HookHelper.FocusMap == null) return;
            int lyrcount = _HookHelper.FocusMap.LayerCount;
            if (lyrcount == 0) return;
            if (NodesExpand != null && NodesExpand.Length > 0)
            {
                foreach (string s in NodesExpand)
                {
                    Node n = new Node();
                    n.Text = s;
                    this.Nodes.Add(n);
                }
            }
            Node node = null;
            if (this.HasRoot)
            {
                node = new Node();
                node.Text = "所有图层";
                if (CheckBoxVisiable)
                {
                    node.CheckBoxVisible = true;
                }
            }            
            for (int i = 0; i < lyrcount; i++)
            {
                ILayer lyr = _HookHelper.FocusMap.get_Layer(i);
                AddLayer(lyr, node);
            }
            if (node != null)
            {
                this.Nodes.Add(node);
                node.TreeControl.ExpandAll();
            }
        }

        /// <summary>
        /// 添加图层到图层列表
        /// </summary>
        /// <param name="grpLayer">要添加的图层组对象</param>
        /// <param name="parentNode">要添加到的父节点对象</param>
        private void AddLyers(ICompositeLayer grpLayer, Node parentNode)
        {
            int lyrcount = grpLayer.Count;
            for (int i = 0; i < lyrcount; i++)
            {
                ILayer lyr = grpLayer.get_Layer(i);
                AddLayer(lyr, parentNode);
            }
        }

        /// <summary>
        /// 添加但图层到图层列表
        /// </summary>
        /// <param name="lyr">要添加的图层对象</param>
        /// <param name="parentNode">要添加到的父节点对象</param>
        /// <param name="index">要添加到的位置</param>
        private void AddLayer(ILayer lyr, Node parentNode, int index = -1)
        {
            if (IsOnlyVisiable)
            {
                if (!lyr.Visible)
                    return;
            }            
            Node node = new Node();
            node.Text = lyr.Name;
            node.Tag = lyr;
            if (this.CheckBoxVisiable)
            {
                node.CheckBoxVisible = true;
            }
            SetEnable(lyr, node);
            string strpath = System.IO.Path.GetDirectoryName(this.GetType().Assembly.Location) + @"\Images";
            if (lyr is ICompositeLayer)
            {
                if (lyr is FDOGraphicsLayer)
                    SetImage(node, strpath + @"\Annotate.png", Properties.Resources.Annotate);
                else
                    SetImage(node, strpath + @"\LayerGroup.png", Properties.Resources.LayerGroup);
                AddLyers(lyr as ICompositeLayer, node);
            }
            else if (lyr is CadAnnotationLayer)
            {
                node.CheckBoxThreeState = false;
                SetImage(node, strpath + @"\Annotate.png", Properties.Resources.Annotate);
            }
            else if (lyr is IFeatureLayer)
            {
                node.CheckBoxThreeState = false;
                IFeatureLayer featLyr = lyr as IFeatureLayer;
                if (IsOnlySelected)
                {
                    if (!featLyr.Selectable)
                        return;
                }
                if (featLyr.FeatureClass != null)
                {
                    if (featLyr.FeatureClass.ShapeType == ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryLine ||
                        featLyr.FeatureClass.ShapeType == ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolyline)
                        SetImage(node, strpath + @"\Line.png", Properties.Resources.Line);
                    else if (featLyr.FeatureClass.ShapeType == ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPoint)
                        SetImage(node, strpath + @"\Point.png", Properties.Resources.Point);
                    else if (featLyr.FeatureClass.ShapeType == ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolygon)
                        SetImage(node, strpath + @"\Polygon.png", Properties.Resources.Polygon);
                    else if (featLyr.FeatureClass.ShapeType == ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryMultiPatch)
                        SetImage(node, strpath + @"\MultiPatch.png", Properties.Resources.MultiPatch);
                    else
                    {
                        SetImage(node, strpath + @"\Empty.png", Properties.Resources.Empty);
                        node.CheckBoxVisible = false;
                    }

                }
                else
                {
                    node.CheckBoxVisible = false;
                    SetImage(node, strpath + @"\Empty.png", Properties.Resources.Empty);
                }
            }
            else if (lyr is IRasterLayer)
            {
                node.CheckBoxThreeState = false;
                SetImage(node, strpath + @"\Raster.png", Properties.Resources.Raster);
            }
            else if (lyr is ILasDatasetLayer)
            {
                node.CheckBoxThreeState = false;
                SetImage(node, strpath + @"\LasDataset.png", Properties.Resources.LasDataset);
            }
            else
            {
                node.CheckBoxVisible = false;
                SetImage(node, strpath + @"\Empty.png", Properties.Resources.Empty);
            }
            if (parentNode == null)
            {
                if (index > -1)
                    this.Nodes.Insert(index, node);
                else
                    this.Nodes.Add(node);
            }
            else
            {
                if (index > -1)
                    parentNode.Nodes.Insert(index, node);
                else
                    parentNode.Nodes.Add(node);
            }

        }
        
        /// <summary>
        /// 删除图层节点
        /// </summary>
        /// <param name="layer"></param>
        /// <param name="nodes"></param>
        private void DeleteNode(ILayer layer, NodeCollection nodes)
        {
            foreach (Node node in nodes)
            {
                if (node.Tag != null && node.Tag is ILayer)
                {
                    if ((node.Tag as ILayer).Equals(layer))
                    {
                        nodes.Remove(node);
                        break;
                    }
                }
                if (node.Nodes.Count > 0)
                {
                    DeleteNode(layer, node.Nodes);
                }
            }
        }
        
        /// <summary>
        /// 更新图层的名称
        /// </summary>
        /// <param name="layer"></param>
        /// <param name="newName"></param>
        /// <param name="nodes"></param>
        private void UpdateName(ILayer layer, string newName, NodeCollection nodes)
        {
            foreach (Node node in nodes)
            {
                if (node.Tag !=null && (node.Tag as ILayer).Equals(layer))
                {
                    layer.Name = newName;
                    node.Text = newName;
                    return;
                }
                if (node.Nodes.Count > 0)
                {
                    UpdateName(layer, newName, node.Nodes);
                }
            }
        }
        
        /// <summary>
        /// 设置节点的图片
        /// </summary>
        /// <param name="node">节点对象</param>
        /// <param name="fullname">图片的全路径</param>
        /// <param name="bitmap">默认的图片</param>
        private void SetImage(Node node, string fullname, Bitmap bitmap)
        {
            if (File.Exists(fullname))
                node.Image = new Bitmap(fullname);
            else
                node.Image = bitmap;
        }
        
        /// <summary>
        /// 设置图层的可用状态
        /// </summary>
        /// <param name="lyr"></param>
        /// <param name="node"></param>
        private void SetEnable(ILayer lyr, Node node)
        {
            if (this.FeatureType == zjgisFeatureType.Null)
            {
                node.Enabled = false;
                node.Selectable = false;
                return;
            }
            if (this.ShapeType == zjgisShapeType.Null)
            {
                node.Enabled = false;
                node.Selectable = false;
                return;
            }
            if (lyr is ICompositeLayer)
            {
                if (this.ShapeType == zjgisShapeType.All)
                {
                    if (CompositeLayerEnabled == false)
                    {
                        node.Enabled = false;
                        node.Selectable = false;
                    }
                    else
                    {
                        node.Enabled = true;
                        node.Selectable = true;
                    }
                    return;
                }
                    
                if (lyr is FDOGraphicsLayer)
                {
                    if ((this.ShapeType & zjgisShapeType.Annotate) != zjgisShapeType.Annotate)
                    {
                        node.Enabled = false;
                        node.Selectable = false;
                        return;
                    }
                }
                else
                {
                    if (lyr.Name.ToLower().EndsWith(".dwg") || lyr.Name.ToLower().EndsWith(".dxf"))
                    {
                        if ((this.FeatureType & zjgisFeatureType.Cad) != zjgisFeatureType.Cad)
                        {
                            node.Enabled = false;
                            node.Selectable = false;
                            return;
                        }
                    }
                    else
                    {
                        if ((this.FeatureType & zjgisFeatureType.Group) != zjgisFeatureType.Group)
                        {
                            node.Enabled = false;
                            node.Selectable = false;
                            return;
                        }
                    }

                }
            }
            else if (lyr is CadAnnotationLayer)
            {
                if (this.ShapeType != zjgisShapeType.All && (this.ShapeType & zjgisShapeType.Annotate) != zjgisShapeType.Annotate)
                {
                    node.Enabled = false;
                    node.Selectable = false;
                    return;
                }
            }
            else if (lyr is IFeatureLayer)
            {
                if (this.FeatureType != zjgisFeatureType.All && (this.FeatureType & zjgisFeatureType.Vector) != zjgisFeatureType.Vector)
                {
                    node.Enabled = false;
                    node.Selectable = false;
                    return;
                }
                else
                {
                    IFeatureLayer featLyr = lyr as IFeatureLayer;
                    if (featLyr.FeatureClass != null)
                    {
                        if (featLyr.FeatureClass.ShapeType == ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryLine ||
                            featLyr.FeatureClass.ShapeType == ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolyline)
                        {
                            if (this.ShapeType != zjgisShapeType.All && (this.ShapeType & zjgisShapeType.Line) != zjgisShapeType.Line)
                            {
                                node.Enabled = false;
                                node.Selectable = false;
                                return;
                            }
                        }
                        else if (featLyr.FeatureClass.ShapeType == ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPoint)
                        {
                            if (this.ShapeType != zjgisShapeType.All && (this.ShapeType & zjgisShapeType.Point) != zjgisShapeType.Point)
                            {
                                node.Enabled = false;
                                node.Selectable = false;
                                return;
                            }
                        }
                        else if (featLyr.FeatureClass.ShapeType == ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolygon)
                        {
                            if (this.ShapeType != zjgisShapeType.All && (this.ShapeType & zjgisShapeType.Polygon) != zjgisShapeType.Polygon)
                            {
                                node.Enabled = false;
                                node.Selectable = false;
                                return;
                            }
                        }
                        else if (featLyr.FeatureClass.ShapeType == ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryMultiPatch)
                        {
                            if (this.ShapeType != zjgisShapeType.All && (this.ShapeType & zjgisShapeType.MultiPatch) != zjgisShapeType.MultiPatch)
                            {
                                node.Enabled = false;
                                node.Selectable = false;
                                return;
                            }
                        }

                    }
                    else
                    {
                        node.Enabled = false;
                        node.Selectable = false;
                        return;
                    }
                }

            }
            else if (lyr is IRasterLayer)
            {
                if (this.FeatureType != zjgisFeatureType.All && (this.FeatureType & zjgisFeatureType.Raster) != zjgisFeatureType.Raster)
                {
                    node.Enabled = false;
                    node.Selectable = false;
                    return;
                }
            }
            else if (lyr is ILasDatasetLayer)
            {
                if (this.FeatureType != zjgisFeatureType.All && (this.FeatureType & zjgisFeatureType.LasDataset) != zjgisFeatureType.LasDataset)
                {
                    node.Enabled = false;
                    node.Selectable = false;
                    return;
                }
            }
        }
        #endregion

        /// <summary>
        /// 绑定地图对象
        /// </summary>
        /// <param name="hook">需要绑定的对象：AxMapControl.Object</param>
        /// <param name="tocObject">toc控件的object</param>
        public void OnCreate(object hook, object tocObject = null)
        {
            _HookHelper = new HookHelper();
            _HookHelper.Hook = hook;

            IMapControlEvents2_Event mapctrlEvent = _HookHelper.Hook as IMapControlEvents2_Event;
            mapctrlEvent.OnMapReplaced += new IMapControlEvents2_OnMapReplacedEventHandler(mapctrlEvent_OnMapReplaced);

            if (tocObject != null)
            {
                _TocControl = tocObject as ITOCControl2;
                _TocControl.LabelEdit = esriTOCControlEdit.esriTOCControlManual;
                ITOCControlEvents_Event tocEvent = _TocControl as ITOCControlEvents_Event;
                tocEvent.OnEndLabelEdit += new ITOCControlEvents_OnEndLabelEditEventHandler(tocEvent_OnEndLabelEdit);
            }
            RegEvent();
            InitLayers();
        }

        /// <summary>
        /// 隐藏指定的图层，其它的图层显示
        /// </summary>
        /// <param name="layer">要隐藏的图层</param>
        /// <param name="nodes">图层所在的节点集合，若从所有节点查找，则设置为Nodes</param>
        public void HideLayer(ILayer layer, NodeCollection nodes)
        {
            foreach (Node node in nodes)
            {
                node.Visible = true;
                if (layer != null && (node.Tag as ILayer).Equals(layer))
                {
                    node.Visible = false;
                }
                if (node.Nodes.Count > 0)
                {
                    HideLayer(layer, node.Nodes);
                }
            }
        }

        /// <summary>
        /// 设置选中的要素类名称
        /// </summary>
        /// <param name="name"></param>
        /// <param name="nodes"></param>
        public void SetFeatureClassName(string name, NodeCollection nodes)
        {
            foreach (Node node in nodes)
            {
                node.Visible = true;
                if (node.Tag != null && node.Tag is IFeatureLayer)
                {
                    IFeatureLayer lyr = node.Tag as IFeatureLayer;
                    string clsname = (lyr.FeatureClass as IDataset).Name;
                    if (clsname.EqualFeatureClassName(name))
                    {
                        SelectedNode = node;
                        return;
                    }
                }
                if (node.Nodes.Count > 0)
                {
                    SetFeatureClassName(name, node.Nodes);
                }
            }
        }
                
        /// <summary>
        /// 获取选择的图层
        /// </summary>
        /// <returns></returns>
        public List<ILayer> GetSelectLayers()
        {
            List<ILayer> lyrs = new List<ILayer>();
            foreach (Node node in this.Nodes)
            {
                if (node.Checked || node.CheckState == System.Windows.Forms.CheckState.Indeterminate)
                {
                    if (node.Tag != null && node.Tag is ILayer)
                        lyrs.Add(node.Tag as ILayer);
                }
                if (node.Nodes.Count > 0)
                {
                    GetSelectLayers(node.Nodes, lyrs);
                }
            }
            return lyrs;
        }
        
        /// <summary>
        /// 获取选择的图层
        /// </summary>
        /// <param name="nodes"></param>
        /// <param name="lyrs"></param>
        private void GetSelectLayers(NodeCollection nodes, List<ILayer> lyrs)
        {
            foreach (Node node in nodes)
            {
                if (node.Checked || node.CheckState == System.Windows.Forms.CheckState.Indeterminate)
                {
                    if (node.Tag != null && node.Tag is ILayer)
                        lyrs.Add(node.Tag as ILayer);
                }
                if (node.Nodes.Count > 0)
                {
                    GetSelectLayers(node.Nodes, lyrs);
                }
            }
        }
    }
}
